﻿using Dapper;
using Hangfire;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using X23.ApplicationJob.Application.Dto;

namespace X23.ApplicationJob.Application
{
    public class JobService : IJobService
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly IDbConnection _dbConnection;

        public JobService(IServiceProvider serviceProvider, IDbConnection dbConnection)
        {
            _serviceProvider = serviceProvider;
            _dbConnection = dbConnection;
        }
        /// <summary>
        /// 运行周期任务
        /// </summary>
        /// <param name="key">指定标识符</param>
        /// <returns></returns>
        public bool RunJob(string key)
        {
            RecurringJob.AddOrUpdate(key, () => DoWork(key), StaticDic.JobStaticDic[key].JobAttribute.Cron);

            return true;
        }
        /// <summary>
        /// 运行周期任务
        /// </summary>
        /// <param name="key">指定标识符</param>
        /// <returns></returns>
        public async Task<bool> DoWork(string key)
        {
            var jobAttributeDto = StaticDic.JobStaticDic[key];

            //C#反射调用外部Dll,执行其中异步函数并取返回值
            //https://www.cnblogs.com/cteng-common/p/9011920.html
            var obj = ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, jobAttributeDto.ClassType);

            var data = jobAttributeDto.ClassType.GetMethod(jobAttributeDto.JobAttribute.Methtod).Invoke(obj, null);

            //object o;
            if (data is Task)
            {
                var task = data as Task;
                await task;
                //o = task.GetType().GetProperty("Result").GetValue(task, null);
            }
            return true;
        }

        /// <summary>
        /// 立即执行任务
        /// </summary>
        /// <param name="key">指定标识符</param>
        /// <returns></returns>
        public bool TriggerJob(string key)
        {
            RecurringJob.Trigger(key);
            return true;
        }

        /// <summary>
        /// 删除现有的周期任务
        /// </summary>
        /// <param name="key">指定标识符</param>
        /// <returns></returns>
        public bool RemoveJob(string key)
        {
            RecurringJob.RemoveIfExists(key);
            return true;
        }

        /// <summary>
        /// 获取所有的job
        /// </summary>
        /// <returns></returns>
        public List<AllJobDto> GetAllJob()
        {
            var hanfireHashKeySetList = _dbConnection.Query<HanfireHashKeySet>(
                        @"
                        SELECT tSet.`Key`,tHash.`Json`
                        FROM (SELECT `Value` AS `Key`,CONCAT(""recurring-job"",':',`Value`) AS `SetKey` FROM `Set`) tSet
                        LEFT JOIN
                        (
                        SELECT `Key` AS `HashKey`, CONCAT('{', GROUP_CONCAT('""',`Field`, '"":""',`Value`, '""'), '}') AS `Json`
                        FROM `Hash`
                        WHERE `Field` IN('CreatedAt', 'NextExecution', 'LastExecution')
                        GROUP BY `Key`
                        ) `tHash`
                        ON tSet.SetKey = tHash.HashKey
                        "
                ).ToList();

            var dic = StaticDic.JobStaticDic.Select(x => x.Value.JobAttribute).OrderBy(x => x.Key).ToList();

            var result = from a in dic
                         join b in hanfireHashKeySetList
                         on a.Key equals b.Key
                         into temp
                         from tt in temp.DefaultIfEmpty()
                         select new AllJobDto
                         {
                             Key = a.Key,
                             Cron = a.Cron,
                             CronName = a.CronName,
                             JobName = a.JobName,
                             Methtod = a.Methtod,
                             JobStatus = tt == null ? JobStatus.No : JobStatus.Executing,
                             Json = tt == null ? "{}" : tt.Json
                         };
            return result.ToList();
        }

        public List<string> GetRunningJobKey()
        {
            return _dbConnection.Query<string>("select `Value` from `Set`;").ToList();
        }
    }
}
